package com.forhappy.light3ds8.arm.bluetooth;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;

import com.forhappy.light3ds8.tools.DatasUtils;

import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.util.Log;


/**
 * 功能通过不断连接已经配对的蓝牙从机，直至连接OK。连接OK后会以ISocketEvent 回调回去�?
 * 调用方式�?
 * 		生成该对象即可：new Bluetoothclient(new ISocketEvent());
 *
 * 注意点：
 * 1. 找蓝牙过程是通过手机中的设置搞定的，这块实现针对小车没有多大意义�?
 * 2. �?��匹配后，无论先打�?��牙模块，还是先启动客户端都无�?��，都会自动匹配上�?
 * 3. 上位机�?过onConnect回调中的BluetoothSocket 进行管理蓝牙通信，如直接写数据�?
 * 4. 上位机�?过onReceived 获知蓝牙串口上传上的消息
 *
 * @author Administrator
 *
 */
@SuppressLint("NewApi")
public class Bluetoothclient {
	public static enum State {WaitStart, Connecting, Connected};

	private static final String TAG = "bluetoothclient";
	private BluetoothSocket mmSocket = null;
	BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
	ISocketEvent eventCallback = null;
	boolean needRun = true;
	ReadThread readThread = null;
	@Override
	public String toString() {
		StringBuffer sb = new StringBuffer();
		if(null == readThread){
			sb.append(" is not running!");
		} else {
			sb.append(" readThread state:" + readThread.getState());
		}

		if(null == mmSocket){
			sb.append("not connect!!");
			return sb.toString();
		}
		sb.append("isConnected:").append(mmSocket.isConnected());
		if(!mmSocket.isConnected()){
			return sb.toString();
		}
		sb.append("device:").append(mmSocket.getRemoteDevice().getName());
		return sb.toString();
	}
	/**
	 * 获取当时的状�?
	 * 0 连接成功 1: 未连 2:连接
	 * @return
	 */
	public State getState(){
		//读线程都未启�?
		if(!readThread.isAlive()){
			return State.WaitStart;
		}
		//正在连接中，但是socket未连接成�?
		if(null == mmSocket ||!mmSocket.isConnected()){
			return State.Connecting;
		}
		return State.Connected; //connected
	}
	public BluetoothSocket getSocket(){
		if(State.Connected == getState()){
			return mmSocket;
		} else {
			return null;
		}
	}
	public Bluetoothclient(ISocketEvent eventCallback) {
		this.eventCallback = eventCallback;
		connect();
	}

	public boolean prepare() throws InterruptedException {
		if (!adapter.isEnabled()) {
			Log.d(TAG, "bluetooth is not open, open it!!");
			adapter.enable();
		}
		if (adapter.getBondedDevices().size() == 0) {
			Log.d(TAG, "no devices is bound, just wait");
			return false;
		}
		return true;
	}

	public boolean exit() {
		needRun = false;
		close();
		if(null != readThread){
			readThread.exit();
			readThread = null;
		}
		return true;
	}

	public synchronized void connect() {
		needRun = true;
		if (null != readThread && readThread.isAlive()) {
			return;
		}
		readThread = new ReadThread();
		readThread.start();
	}

	public boolean write(byte[] buf) {
		if (null == mmSocket || !mmSocket.isConnected()) {
			return false;
		}
		try {
			OutputStream out = mmSocket.getOutputStream();
			out.write(buf);
			out.flush();
		} catch (IOException e) {
			Log.e(TAG, e.toString(), e);
			return false;
		}
		return true;
	}


	/** Will cancel an in-progress connection, and close the socket */
	private synchronized void close() {
		try {
			if(null != eventCallback){
				eventCallback.onDisConnect(mmSocket);
			}
			if (null != mmSocket && mmSocket.isConnected()) {
				mmSocket.close();
				mmSocket = null;
			}
		} catch (IOException e) {
		}
	}

	class ReadThread extends Thread {
		public ReadThread() {
			super("BluetoothReadThread" + System.currentTimeMillis()%86400000);
		}
		boolean isRun = true;

		public void exit() {
			isRun = false;
			interrupt();
		}

		@Override
		public void run() {
			Log.i(TAG, "begin to connect To srv");
			InputStream in = null;
			while (isRun && !isInterrupted()) {
				try {
					sleep(500);
					if (!prepare()) {
						continue;
					}
					if(null == mmSocket || !mmSocket.isConnected()){
						// Use a temporary object that is later assigned to
						// mmSocket,
						// because mmSocket is final
						mmSocket = connectToServer();
						if(null == mmSocket || !mmSocket.isConnected()){
							Log.i(TAG, "call connectToServer return null");
							continue;
						} else{
							Log.i(TAG, "connect to " + mmSocket.getRemoteDevice().getName() + " success!");
						}
					}
					deposeSocket(mmSocket);
				} catch (InterruptedException e) {
					Log.e(TAG, e.toString(), e);
				} finally {
					close();
					if (null != in) {
						try {
							in.close();
						} catch (Exception e) {
						}
					}
				}
			}
			Log.i(TAG, "exit bluetootch Client read Thread");
		}

		private BluetoothSocket connectToServer(){
			Log.d(TAG, "enter connectToServer() thread:" + getName());
			// Use a temporary object that is later assigned to
			// mmSocket,
			// because mmSocket is final
			BluetoothSocket connectSocket = null;
			BluetoothDevice[] bluetoothDevices = adapter.getBondedDevices().toArray(new BluetoothDevice[] {});
			if(null == bluetoothDevices || bluetoothDevices.length == 0){
				Log.e(TAG, "when connect bluetooth, no bluetooth is reconginzed, should find bluetooth first!");
				return null;
			}

			for(BluetoothDevice device:bluetoothDevices){
				if(isInterrupted()){
					break;
				} else if(null != mmSocket && mmSocket.isConnected()){
					Log.d(TAG, "in connect To Server, socket is aready connect to " + mmSocket.getRemoteDevice().getName() + ", thread:" + getName());
					connectSocket = mmSocket;
					break;
				}

	//			BluetoothDevice device = adapter.getBondedDevices().toArray(new BluetoothDevice[] {})[0];
				try {
					Log.d(TAG, "begin to creat socket from " + device.getName());
					// MY_UUID is the app's UUID string, also used by the
					// server code
					connectSocket = device.createRfcommSocketToServiceRecord(UUID
							.fromString("00001101-0000-1000-8000-00805F9B34FB"));

					if(null != eventCallback){
						eventCallback.onConnecting(connectSocket);
					}
					// Connect the device through the socket. This will block
					// until it succeeds or throws an exception
					connectSocket.connect();

					mmSocket = connectSocket;
					if(null != mmSocket && mmSocket.getRemoteDevice() != null){
						Log.i(TAG, "connect to " + mmSocket.getRemoteDevice().getName() + " success");
					} else {
						Log.i(TAG, "connect to server success!!");
					}
					if(null != eventCallback){
						eventCallback.onConnected(mmSocket);
					}
				} catch (IOException e) {
					Log.e(TAG, e.toString());
					continue;
				}
			}
			return connectSocket;
		}

		private boolean deposeSocket(BluetoothSocket socket){
			Log.d(TAG, "enter deposeSocket(socket:" + socket.getRemoteDevice().getName() + ", name:" + getName());
			InputStream in;
			try {
				in = socket.getInputStream();
				byte[] buf = new byte[1024];
				int iRead = -1;
				while (!isInterrupted() && -1 != (iRead = in.read(buf))) {
					Log.i(TAG, "received: " + DatasUtils.byteToHexStr(buf, 0, iRead));
					if(null != eventCallback){
						eventCallback.onReceived(socket, buf, 0, iRead);
					}
				}
			} catch (IOException e) {
				Log.e(TAG, e.toString(), e);
			}
			return false;
		}
	}
}